package ui;

import info.Conference;
import io.ConferenceAccess;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import org.jdom2.JDOMException;

import users.ProgramChair;
import users.User;

/**
 * A built-in software tool for adding conferences to the database.  Used by admins only.
 * 
 * @author Aaron Chen
 * @version 3/14/2014
 */
@SuppressWarnings("serial")
public class ConferenceSetupPanel extends AbstractForm implements Recipient {
  
  /** The title of the panel. */
  private static final String PANEL_TITLE = "Conference Setup Form";
  
  /** The text field for the conference title. */
  private JTextField my_tf_conference;
  
  /** The text field for the Program Chair responsible for the conference. */
  private JTextField my_tf_program_chair;
  
  /** The text field for the hosting date. */
  private JTextField my_tf_date;
  
  /** The text field for the hosting venue. */
  private JTextField my_tf_venue;
  
  /** The text field for the conference's major categories.*/
  private JTextField my_tf_categories;
  
  /** The text area for the conference description. */
  private JTextArea my_ta_description;

  /** The text field for the manuscript submission deadline. */
  private JTextField my_tf_submission_deadline;

  /** The text field for the Reviewer's reviews and Subprogram Chair's recommendation
   * submission deadline. */
  private JTextField my_tf_review_deadline;

  /** The text field for the Program Chair decision deadline. */
  private JTextField my_tf_decision_deadline;

  /** The text field for the final submission deadline, for manuscripts that have been
   * accepted by the Program Chair. */
  private JTextField my_tf_final_deadline;
  
  /** The conference object to be represented by the form. */
  private Conference my_conference;
  
  /** The User that will become the Program Chair. */
  private User my_program_chair;
  
  /** The database access for conference data. */
  private ConferenceAccess my_conference_access;

  
  /**
   * Initializes the panel with empty fields.
   * @param the_parent The main application window container.
   * @wbp.parser.constructor
   */
  public ConferenceSetupPanel(final DisplayPanel the_parent) {
    super(the_parent);
    my_conference_access = getConferenceAccess();
    my_btn_submit.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        if (submitForm()) {
          JOptionPane.showMessageDialog(ConferenceSetupPanel.this,
                                        "Form submitted successfully!");
          setMode(MODE_EXISTING_FORM);
        } else {
          JOptionPane.showMessageDialog(ConferenceSetupPanel.this,
                                        "One or more fields are invalid.");
        }
      }
    });
    my_btn_save_changes.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        editForm();
        JOptionPane.showMessageDialog(ConferenceSetupPanel.this,
                                      "Form edited successfully!");
      }
    });
  }
  
  /**
   * Initializes the panel with filled out fields.  Use this constructor if you
   * want to view a form that has been previously filled out.
   * @param the_parent The main application window container.
   * @param the_c The recommendation form that was filled out previously.
   */
  public ConferenceSetupPanel(final DisplayPanel the_parent,
                              final Conference the_c) {
    this(the_parent);
    setMode(MODE_EXISTING_FORM);
    populateFields(the_c);
    my_conference = the_c;
  }
  
  /**
   * Attempts to create a ConferenceAccess connection to the database.
   * @return The ConferenceAccess object.
   */
  private ConferenceAccess getConferenceAccess() {
    ConferenceAccess database = null;
    try {
      database = new ConferenceAccess();
    } catch (final IOException e) {
      JOptionPane.showMessageDialog(this, "There is a problem accessing the database.");
      e.printStackTrace();
    } catch (final JDOMException e) {
      JOptionPane.showMessageDialog(this, "The file specified by the code is incorrect.");
      e.printStackTrace();
    }
    return database;
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  protected String getFormTitle() {
    return PANEL_TITLE;
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  protected JPanel createFormPanel() {
    final JPanel panel_form = new JPanel();
    panel_form.setLayout(new BoxLayout(panel_form, BoxLayout.Y_AXIS));
    panel_form.setBackground(Standards.COLOR_BACKGROUND);
    panel_form.setBorder(Standards.BORDER_COMPOUND_FORM);
    
    panel_form.add(createPrimaryColumnedPanel());
    panel_form.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    
    setUpTextFields(panel_form);
    setUpTextAreas(panel_form);
    panel_form.add(createDatesColumnedPanel());
    
    return panel_form;
  }
  
  /**
   * Populates the manuscript submission form with text fields and their
   * respective labels.
   * @param the_panel The panel of the form.
   */
  private void setUpTextFields(final JPanel the_panel) {
    final JPanel panel_categories = new JPanel();
    panel_categories.setBackground(Standards.COLOR_BACKGROUND);
    panel_categories.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_categories = new JLabel("Categories");
    panel_categories.add(lbl_categories, BorderLayout.CENTER);
    
    my_tf_categories = new JTextField();
    my_tf_categories.setToolTipText(
        "The primary categories that the conference can be divided into.");
    panel_categories.add(my_tf_categories, BorderLayout.SOUTH);

    the_panel.add(panel_categories);
    the_panel.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
  }
  
  /**
   * Populates the manuscript submission form with text areas and their
   * respective labels.
   * @param the_panel The panel of the form.
   */
  private void setUpTextAreas(final JPanel the_panel) {
    final JPanel panel_description = new JPanel();
    panel_description.setBackground(Standards.COLOR_BACKGROUND);
    panel_description.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_description = new JLabel("Description");
    panel_description.add(lbl_description, BorderLayout.CENTER);
    
    my_ta_description = new JTextArea();
    my_ta_description.setToolTipText("A description of what the conference is like.");
    my_ta_description.setRows(Standards.TEXT_AREA_MEDIUM_ROWS);
    my_ta_description.setWrapStyleWord(true);
    my_ta_description.setLineWrap(true);
    
    panel_description.add(createScrollPane(my_ta_description), BorderLayout.SOUTH);

    final JPanel panel_text = new JPanel();
    panel_text.setBackground(Standards.COLOR_BACKGROUND);
    panel_text.setLayout(new BorderLayout(0, 0));
    
    the_panel.add(panel_description);
    the_panel.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    the_panel.add(panel_text);
  }
  
  /**
   * Creates the columned portion of the form panel.
   * @return The columned panel.
   */
  private JPanel createPrimaryColumnedPanel() {
    final JPanel panel_column_split = new JPanel();
    panel_column_split.setBackground(Standards.COLOR_BACKGROUND);
    panel_column_split.setLayout(new BoxLayout(panel_column_split, BoxLayout.X_AXIS));

    panel_column_split.add(createLeftColumnPanel());
    panel_column_split.add(Box.createHorizontalStrut(Standards.STRUT_LENGTH_LARGE));
    panel_column_split.add(createRightColumnPanel());
    
    return panel_column_split;
  }
  
  /**
   * Creates the left column of the columned panel.
   * @return The left column panel.
   */
  private JPanel createLeftColumnPanel() {
    final JPanel panel_left_column = new JPanel();
    panel_left_column.setBackground(Standards.COLOR_BACKGROUND);
    panel_left_column.setLayout(new BoxLayout(panel_left_column, BoxLayout.Y_AXIS));
    
    final JPanel panel_conference = new JPanel();
    panel_conference.setBackground(Standards.COLOR_BACKGROUND);
    panel_conference.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_conference = new JLabel("Conference");
    
    my_tf_conference = new JTextField();
    my_tf_conference.setColumns(Standards.TEXT_BOX_HALF_WIDTH);
    
    final JPanel panel_date = new JPanel();
    panel_date.setBackground(Standards.COLOR_BACKGROUND);
    panel_date.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_date = new JLabel("Hosting Date");
    
    my_tf_date = new JTextField();
    my_tf_date.setColumns(Standards.TEXT_BOX_HALF_WIDTH);

    panel_left_column.add(panel_conference);
    panel_conference.add(lbl_conference, BorderLayout.CENTER);
    panel_conference.add(my_tf_conference, BorderLayout.SOUTH);
    panel_left_column.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_left_column.add(panel_date);
    panel_date.add(lbl_date, BorderLayout.CENTER);
    panel_date.add(my_tf_date, BorderLayout.SOUTH);
    
    return panel_left_column;
  }
  
  /**
   * Creates the right column of the columned panel.
   * @return The right column panel.
   */
  private JPanel createRightColumnPanel() {
    final JPanel panel_right_column = new JPanel();
    panel_right_column.setBackground(Standards.COLOR_BACKGROUND);
    panel_right_column.setLayout(new BoxLayout(panel_right_column, BoxLayout.Y_AXIS));
    
    final JPanel panel_program_chair = new JPanel();
    panel_program_chair.setBackground(Standards.COLOR_BACKGROUND);
    panel_program_chair.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_program_chair = new JLabel("Program Chair");
    
    final JPanel panel_venue = new JPanel();
    panel_venue.setBackground(Standards.COLOR_BACKGROUND);
    panel_venue.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_venue = new JLabel("Hosting Venue");
    
    my_tf_venue = new JTextField();
    my_tf_venue.setColumns(Standards.TEXT_BOX_HALF_WIDTH);

    panel_right_column.add(panel_program_chair);
    panel_program_chair.add(lbl_program_chair, BorderLayout.CENTER);
    
    final JPanel panel_pc_sub = new JPanel();
    panel_pc_sub.setLayout(new BorderLayout(0, 0));
    
    my_tf_program_chair = new JTextField();
    my_tf_program_chair.setEditable(false);
    
    final JButton btn_select_pc = new JButton("...");
    btn_select_pc.setPreferredSize(Standards.DIMENSION_SELECT_BUTTON);
    btn_select_pc.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        final DisplayPanel dsp = getDisplayStack();
        final UserListPanel ulp = new UserListPanel(dsp, ConferenceSetupPanel.this);
        dsp.addToStack(ulp);
      }
    });
    
    panel_pc_sub.add(my_tf_program_chair, BorderLayout.CENTER);
    panel_pc_sub.add(btn_select_pc, BorderLayout.EAST);
    panel_program_chair.add(panel_pc_sub, BorderLayout.SOUTH);
    panel_right_column.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_right_column.add(panel_venue);
    panel_venue.add(lbl_venue, BorderLayout.CENTER);
    panel_venue.add(my_tf_venue, BorderLayout.SOUTH);
    
    return panel_right_column;
  }
  
  /**
   * Creates the columned dates portion of the form panel.
   * @return The columned dates panel.
   */
  private JPanel createDatesColumnedPanel() {
    final JPanel panel_column_split = new JPanel();
    panel_column_split.setBackground(Standards.COLOR_BACKGROUND);
    panel_column_split.setLayout(new BoxLayout(panel_column_split, BoxLayout.X_AXIS));

    panel_column_split.add(createLeftDatesColumnPanel());
    panel_column_split.add(Box.createHorizontalStrut(Standards.STRUT_LENGTH_LARGE));
    panel_column_split.add(createRightDatesColumnPanel());
    
    return panel_column_split;
  }
  
  /**
   * Creates the left column of the columned dates panel.
   * @return The left dates column panel.
   */
  private JPanel createLeftDatesColumnPanel() {
    final JPanel panel_left_column = new JPanel();
    panel_left_column.setBackground(Standards.COLOR_BACKGROUND);
    panel_left_column.setLayout(new BoxLayout(panel_left_column, BoxLayout.Y_AXIS));
    
    final JPanel panel_submission = new JPanel();
    panel_submission.setBackground(Standards.COLOR_BACKGROUND);
    panel_submission.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_submission_deadline = new JLabel("Submission Deadline");
    
    my_tf_submission_deadline = new JTextField();
    my_tf_submission_deadline.setColumns(Standards.TEXT_BOX_HALF_WIDTH);
    
    final JPanel panel_review = new JPanel();
    panel_review.setBackground(Standards.COLOR_BACKGROUND);
    panel_review.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_review_deadline = new JLabel("Review Deadline");
    
    my_tf_review_deadline = new JTextField();
    my_tf_review_deadline.setColumns(Standards.TEXT_BOX_HALF_WIDTH);

    panel_left_column.add(panel_submission);
    panel_submission.add(lbl_submission_deadline, BorderLayout.CENTER);
    panel_submission.add(my_tf_submission_deadline, BorderLayout.SOUTH);
    panel_left_column.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_left_column.add(panel_review);
    panel_review.add(lbl_review_deadline, BorderLayout.CENTER);
    panel_review.add(my_tf_review_deadline, BorderLayout.SOUTH);
    
    return panel_left_column;
  }
  
  /**
   * Creates the right column of the columned dates panel.
   * @return The right dates column panel.
   */
  private JPanel createRightDatesColumnPanel() {
    final JPanel panel_right_column = new JPanel();
    panel_right_column.setBackground(Standards.COLOR_BACKGROUND);
    panel_right_column.setLayout(new BoxLayout(panel_right_column, BoxLayout.Y_AXIS));
    
    final JPanel panel_decision_deadline = new JPanel();
    panel_decision_deadline.setBackground(Standards.COLOR_BACKGROUND);
    panel_decision_deadline.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_decision_deadline = new JLabel("Decision Deadline");
    
    my_tf_decision_deadline = new JTextField();
    my_tf_decision_deadline.setColumns(Standards.TEXT_BOX_HALF_WIDTH);
    
    final JPanel panel_final = new JPanel();
    panel_final.setBackground(Standards.COLOR_BACKGROUND);
    panel_final.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_final_deadline = new JLabel("Final Submission Deadline");
    
    my_tf_final_deadline = new JTextField();
    my_tf_final_deadline.setColumns(Standards.TEXT_BOX_HALF_WIDTH);

    panel_right_column.add(panel_decision_deadline);
    panel_decision_deadline.add(lbl_decision_deadline, BorderLayout.CENTER);
    panel_decision_deadline.add(my_tf_decision_deadline, BorderLayout.SOUTH);
    panel_right_column.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_right_column.add(panel_final);
    panel_final.add(lbl_final_deadline, BorderLayout.CENTER);
    panel_final.add(my_tf_final_deadline, BorderLayout.SOUTH);
    
    return panel_right_column;
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  protected JPanel createButtonsPanel() {
    final JPanel panel_buttons = new JPanel();
    panel_buttons.setBackground(Standards.COLOR_BACKGROUND);
    panel_buttons.setBackground(Standards.COLOR_BACKGROUND);
    panel_buttons.setAlignmentX(Component.LEFT_ALIGNMENT);
    
    my_btn_submit = new JButton("Submit");
    
    my_btn_save_changes = new JButton("Save Changes");
    my_btn_save_changes.setVisible(false);
    
    final JButton btn_cancel = new JButton("Cancel");
    btn_cancel.addActionListener(new ActionListener() {
      /** The action to be performed.
       * Removes the form from view. */
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        getDisplayStack().removeFromStack();
      }
    });
    
    panel_buttons.add(my_btn_submit);
    panel_buttons.add(my_btn_save_changes);
    panel_buttons.add(btn_cancel);
    return panel_buttons;
  }
  
  


  /**
   * Completes the Conference Setup form and submits it to the database.
   * @return true if the conference was successfully created; false otherwise.
   */
  private boolean submitForm() {
    boolean result = false;
    if (my_program_chair != null) {
      final Conference c = inputToConference();
      my_conference_access.createConference(c);
      my_conference = c;
      my_program_chair.addRole(new ProgramChair(0, my_program_chair, my_conference));
      result = true;
    }
    return result;
  }
  
  /**
   * Edits the Manuscript and submits the changes to the database.
   * @return The Manuscript.
   */
  private Conference editForm() {
    final Conference c = inputToConference();
    my_conference_access.editConference(c, my_conference.getID());
    return c;
  }
  
  /**
   * Converts form input into a Conference object.
   * @return The Conference.
   */
  private Conference inputToConference() {
    long id = 0;
    if (my_conference != null) {
      id = my_conference.getID();
    }

    final List<String> categories = parseString(my_tf_categories.getText());
    
    //TODO program chair ID
    
    List<Long> manuscripts = new ArrayList<Long>();
    if (my_conference != null) {
      manuscripts = my_conference.getPublishedManuscripts();
    }
    
    final List<Date> dates = new ArrayList<Date>();
    final SimpleDateFormat df = Standards.DATE_FORMAT;
    try {
      dates.add(df.parse(my_tf_submission_deadline.getText()));
      dates.add(df.parse(my_tf_review_deadline.getText()));
      dates.add(df.parse(my_tf_decision_deadline.getText()));
      dates.add(df.parse(my_tf_final_deadline.getText()));
      dates.add(df.parse(my_tf_date.getText()));
    } catch (final ParseException e) {
      JOptionPane.showMessageDialog(this, "Failed to parse dates.");
      return null;
    }
    
    final Conference c = new Conference(id,
                                        my_tf_conference.getText(),
                                        my_tf_venue.getText(),
                                        my_ta_description.getText(),
                                        categories,
                                        my_program_chair.getID(),
                                        manuscripts,
                                        dates);
    return c;
  }
  
  /**
   * Populates the form using a previously filled out form.
   * @param the_c The manuscript that was previously submitted.
   */
  private void populateFields(final Conference the_c) {
    my_tf_conference.setText(the_c.getTitle());
    my_tf_date.setText(the_c.getHostingDate().toString());
    //TODO Set up the program chair and conference connection properly
    my_tf_program_chair.setText("" + the_c.getProgramChairID());
    my_tf_venue.setText(the_c.getHostingVenue());
    final List<String> categories = the_c.getCategories();
    if (categories != null && !categories.isEmpty()) {
      my_tf_categories.setText(convertStringListToString(categories));
    }
    my_ta_description.setText(the_c.getInfo());
    Date d = the_c.getSubmissionDeadline();
    if (d != null) {
      my_tf_submission_deadline.setText(d.toString());
    }
    d = the_c.getReviewDeadline();
    if (d != null) {
      my_tf_review_deadline.setText(d.toString());
    }
    d = the_c.getDecisionDeadline();
    if (d != null) {
      my_tf_decision_deadline.setText(d.toString());
    }
    d = the_c.getFinalSubmissionDeadline();
    if (d != null) {
      my_tf_final_deadline.setText(d.toString());
    }
  }
  
  /**
   * Parses the input String from JTextField and returns a List<String>.
   * @param the_str The input from a JTextField.
   * @return A List<String>.
   */
  private List<String> parseString(final String the_str) {
    final String[] list = the_str.split("[,;]");
    final List<String> other_list = new ArrayList<String>(list.length);
    for (String str : list) {
      other_list.add(str.trim());
    }
    return other_list;
  }
  
  /**
   * A convenience method for converting a list of Strings into a single
   * String with all values.
   * @param the_list The list to be converted.
   * @return The String that looks nice in a JTextField.
   */
  private String convertStringListToString(final List<String> the_list) {
    final Iterator<String> itr = the_list.iterator();
    final StringBuilder sb = new StringBuilder();
    if (itr.hasNext()) {
      sb.append(itr.next());
      while (itr.hasNext()) {
        sb.append(", ");
        sb.append(itr.next());
      }
    }
    return sb.toString();
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  public String getPanelLabel() {
    return PANEL_TITLE;
  }

  /**
   * Expects a User object and sets it as the Conference's Program Chair.
   * @param the_o The Object to receive.
   */
  @Override
  public void receive(final Object the_o) {
    if (the_o instanceof User) {
      final User u = (User) the_o;
      my_program_chair = u;
      my_tf_program_chair.setText(u.getFullName());
    }
  }
  
}
